package com.gkzf.ai.module.crm.util;

import com.gkzf.ai.framework.common.exception.ServiceException;
import com.gkzf.ai.module.crm.controller.admin.creditReport.vo.creditreportdetails.CreditReportDetailsSaveReqVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.regex.Pattern;

import static com.gkzf.ai.framework.common.util.date.UniversalDateTimeConverter.convert;
import static com.gkzf.ai.module.crm.service.creditReport.CreditReportDetailsServiceImpl.isToday;

/**
 * @author Huawei
 * @date 2025-04-15 9:21
 */
@Slf4j
public class AnalysisJsonObjectUtils {


    public static final String COMMA = ",";

    public static final String InstitutionalInquiryDetails = "机构查询记录明细";

    public static final String localQuery = "本人查询记录";
    
    public static final String QUERY_DATE = "查询日期";

    public static final String QUERY_INSTITUTION = "查询机构";

    public static final String SELF = "本人";

    public static final String INSTITUTION = "机构";

    public static final String QUERY_CAUSE = "查询原因";

    public static final String POST_LOAN_MANAGEMENT = "贷后管理";

    public static final String CREDIT_CARD_ACCOUNT_NAME = "贷记卡账户";

    public static final String CREDIT_CARD = "贷记卡";
    
    public static final String ACCOUNT_STATUS = "账户状态";

    public static final String CREDITCARD = "creditCard";

    public static final String LOANS = "loans";

    public static final String NORMAL = "正常";

    public static final String OVERDUE = "逾期";

    public static final String BAD_DEBT = "呆帐";

    public static final String TURN_OUT = "转出";

    public static final String BALANCE = "余额";

    public static final String BANK = "银行";

    public static final String OVERDUE_REPAYMENT_RECORD = "还款记录";

    public static final String OVERDUE_REPAYMENT_RECORDS = "还款记录列表";

    public static final String TOTAL_CREDIT_LINE = "授信总额";

    public static final String CREDIT_LINE = "授信额度";

    public static final String OPENING_DATE = "开立日期";

    public static final String AVERAGE_SERVICE_RATE = "最近6个月平均使用额度";

    public static final String AVERAGE_SERVICE_REPAYMENT = "最近6个月平均应还款";

    public static final String USED_CREDIT = "已用额度";

    public static final String ACCOUNT_NUMBER = "账户数";

    public static final String HAIRPIN_INSTITUTION_NUMBER = "发卡机构数";

    public static final String ACCOUNT_CREDIT_LIMIT = "账户授信额度";

    public static final String GOVERNING_BODY = "管理机构";

    public static final String CARD_ISSUER = "发卡机构";

    public static final String LOAN_AMOUNT = "借款金额";

    public static final String REPAYMENT_PERIOD = "还款期数";

    public static final String PERSONAL_HOUSING_LOAN = "个人住房商业贷款";

    public static final String PERSONAL_COMMERCIAL_PROPERTY_LOAN = "个⼈住房公积⾦贷款";

    public static final String PERSONAL_AUTO_LOAN = "个人汽车消费贷款";

    public static final String CONSUMER_LOAN = "消费贷款";

    public static final String OPERATE_LOAN = "经营性贷款";

    public static final String PETTY_LOAN = "小额贷款";

    public static final String FINANCE_LOAN = "消费金融";

    public static final String BUSINESS_TYPE = "业务种类";

    public static final String GUARANTY_STYLE = "担保方式";

    public static final String CREDIT_NO_GUARANTEE = "信用/无担保";

    public static final String THE_FIVE_CLASS_CLASSIFICATION = "五级分类";

    public static final String EXPIRATION_TIME = "到期日期";
    /**
     * 逾期次数对应key
     */
    public static final String OVERDUE_REPAYMENT_NUMBER = ":number";
    /**
     * 连续逾期次数对应key
     */
    public static final String OVERDUE_REPAYMENT_CONTINUOUS_NUMBER = ":continuousNumber";
    /**
     * 逾期最大月份对应key
     */
    public static final String OVERDUE_REPAYMENT_MAX_NUMBER = ":maxNumber";
    /**
     * 逾期最大金额对应key
     */
    public static final String OVERDUE_REPAYMENT_MAX_MONEY = ":maxMoney";
    /**
     * 还款记录表 中 数据对于key
     */
    public static final String FIRST_ROW = "first_row";

    public static final String SECOND_ROW = "second_row";

    public static final String FIRST_LINE = "第一行";

    public static final String SECOND_LINE = "第二行";
    /**
     * 解析基本信息 json数据 存储对于key
     */
    public static final String BASIC = "basic";
    /**
     * 非循环贷解析json数据 存储对于key
     */
    public static final String NON_REVOLVING_LOAN_ACCOUNT = "nonRevolvingLoanAccount";
    /**
     * 循环贷一 解析json数据 存储对于key
     */
    public static final String REVOLVING_ACCOUNT_I_RESULT = "revolvingAccountIResult";
    /*
     * 循环贷二 解析json数据 存储对于key
     */
    public static final String REVOLVING_ACCOUNT_II_RESULT = "revolvingAccountIIResult";
    /**
     *  贷记卡 解析json数据 存储对于key
     */
    public static final String CREDIT_CARD_ACCOUNT = "creditCardAccount";
    /**
     * 存储计算担保人代还key
     */
    public static final String GUARANTOR_REPAYMENT = "guarantorRepayment";
    /**
     * 存储计算以资抵债key
     */
    public static final String SETTLE_DEBTS_WITH_CAPITAL = "settleDebtsWithCapital";
    /**
     * 解析时间格式
     */
    public static final String YYYY_M_D = "yyyy.m.d";

    public static final String YYYY_MM_DD = "yyyy.MM.dd";


    /**
     * 解析还款记录表将还款记录按照时间累加成一个Map
     * 判断根据征信打印时间拼接完成的时间线。如果是2024-2月打印就拼接2024-2 ～2024-12的时间 有时间则填有时间的格式。无数据则填默认格式
     * @param repaymentRecord 还款记录Map <年份,数组>
     * @param reportTime 报告打印时间
     * @param currentYearSwitch 是否是第一个记录开关 还款记录第一条需要判断当前年份 如果是当前年 补全月份将不能增加12个月而且增加报告时间打印的月份数
     * @return
     */
    public static List<YearlyRecord> getAnalysisJson(Map<String,YearlyRecord> repaymentRecord, String reportTime, AtomicBoolean currentYearSwitch) {

        List<YearlyRecord> analysisJsonList = new ArrayList<>();
        repaymentRecord.forEach((key, value) -> {
            if (currentYearSwitch.get()) {
                String currentYear = formattingDate(reportTime, "yyyy.MM", "yyyy");
                // 取月份。用于判断当前报告是当年不满12个月的
                String currentMonth = formattingDate(reportTime, "yyyy.MM", "MM");
                // 判断打印报告时间是否等于还款记录表第一条时间 不等于补全这一年的时间
                getCompletionTime(currentYear, currentMonth, key, analysisJsonList);
            }
            currentYearSwitch.set(false);
            for (int i = 0; i < value.getMonthList().size(); i++) {
                // 解析已有年份中的数据 不足12过月的补齐12个月
                int number = 12 - value.getMonthList().size();
                for (int j = 0; j < number; j++) {
                    List<String> monthList = value.getMonthList();
                    List<String> moneyList = value.getMoneyList();
                    for (int k = 1; k < number; k++) {
                        monthList.add("N");
                        moneyList.add("0");
                    }
                }
            }
            analysisJsonList.add(value);
        });


        return analysisJsonList;
    }

    /**
     * 补全时间 判断 matchingTime 是否小于 reportTime 时间 补全reportTime这一年的时间
     * @param reportTime 报告打印时间(年)
     * @param matchingTime 还款记录时间(年)
     * @param yearlyRecords 存储补全集合
     * @return
     */
    public static void getCompletionTime(String reportTime,String currentMonth,String  matchingTime,List<YearlyRecord> yearlyRecords ){
        int reportTimeInt = Integer.parseInt(reportTime);
        int matchingTimeInt = Integer.parseInt(matchingTime);
        // 获取当前时间
        // 判断时间如果征信报告年份大于还款记录表年份则补全reportTime中月份的数据
        int month = Integer.parseInt(currentMonth);
        if (reportTimeInt > matchingTimeInt){
            YearlyRecord yearlyRecord = new YearlyRecord((matchingTimeInt+1)+"");
            List<String> monthList = yearlyRecord.getMonthList();
            List<String> moneyList = yearlyRecord.getMoneyList();
            for (int i = 0; i < month; i++) {
                monthList.add("N");
                moneyList.add("0");
            }
            yearlyRecords.add(yearlyRecord);
            matchingTimeInt+=1;
            getCompletionTime( reportTime, currentMonth,String.valueOf(matchingTimeInt),yearlyRecords);
        }
    }



    public static List<Map<String, String>> jsonToList(List<YearlyRecord> yearlyRecordList) {
        List<Map<String, String>> listMap = new ArrayList<>();
        yearlyRecordList.forEach(yearlyRecord -> {
            for (int i = 0; i < yearlyRecord.getMonthList().size(); i++) {
            Map<String, String> map = new LinkedHashMap<>();
            // 遍历每一个键值对，并将其放入 Map 中
                map.put(Optional.ofNullable(yearlyRecord.getMonthList().get(i)).orElse("N"), Optional.ofNullable(yearlyRecord.getMoneyList().get(i)).orElse("0"));
                listMap.add(map);
            }
        });
        return listMap;
    }


    /**
     * 判断是否是数字
     * @param str
     * @return true是数字  false不是数字
     */
    public static boolean isPositiveInteger(String str) {
        if (str == null || str.isEmpty()) {
            return false;
        }
        return Pattern.matches("\\d+", str);
        // 或者
        // return str.matches("\\d+");  // 更简洁
    }

    /**
     * 查找集合中逾期月序列的最长长度。
     *
     * @param list 输入的集合
     * @param length 判断的长度
     * @return 最长连续数字序列的长度，如果集合为 null 或没有数字，返回 0。
     */
    public static int findMaxLengthOfConsecutiveNumbers(List<Map<String,String>> list,int length) {
        if (list == null || list.isEmpty()) {
            return 0;
        }
        AtomicInteger maxLength = new AtomicInteger(0);
        AtomicInteger currentLength = new AtomicInteger();
        for (int i = 0; i < length; i++) {
            Map<String, String> obj = list.get(i);
            obj.forEach((key, value) -> {
                String number = convertMoney(value);
                if (isPositiveInteger(number) && Integer.parseInt(number) > 0) {
                    currentLength.getAndIncrement(); // 当前元素是数字，连续长度增加
                } else {
                    // 当前元素不是数字，判断之前的连续数字长度是否是当前最长
                    if (currentLength.get() > maxLength.get()) {
                        maxLength.set(currentLength.get());
                    }
                    currentLength.set(0); // 重置当前连续长度
                }
            });

        }
        // 遍历结束后，最后一段连续数字序列可能没有被比较到，需要再次比较
        if (currentLength.get() > maxLength.get()) {
            maxLength.set(currentLength.get());
        }

        return maxLength.get();
    }

    /**
     * 查找集合中数字序列的月份最大值
     *
     * @param list 输入的集合
     * @param length 判断的长度
     * @return 最长连续数字序列的长度，如果集合为 null 或没有数字，返回 0。
     */
    public static int findMaxLengthOfMonth(List<Map<String, String>> list, int length) {
        if (list == null || list.isEmpty()) {
            return 0;
        }
        AtomicInteger maxLength = new AtomicInteger(0);
        AtomicInteger currentLength = new AtomicInteger();
        for (int i = 0; i < length; i++) {
            Map<String, String> obj = list.get(i);
            obj.forEach((key, value) -> {
                String number = convertMoney(value);
                if (isPositiveInteger(number) && Integer.parseInt(number) > 0) {
                    currentLength.set(Integer.parseInt(number)); // 当前元素是数字，连续长度增加
                    if (maxLength.get() < currentLength.get()) {
                        maxLength.set(currentLength.get());
                    }
                }
            });
        }
        return maxLength.get();
    }
    /**
     * 查找集合中数字序列的月份对应金额最大值
     *
     * @param list 输入的集合
     * @param length 判断的长度
     * @return 最长连续数字序列的长度，如果集合为 null 或没有数字，返回 0。
     */
    public static BigDecimal findMaxLengthOfMoney(List<Map<String, String>> list, int length) {
        if (list == null || list.isEmpty()) {
            return BigDecimal.ZERO;
        }
        AtomicReference<BigDecimal> maxLength = new AtomicReference<>(BigDecimal.ZERO);
        AtomicReference<BigDecimal> currentLength = new AtomicReference<>();

        for (int i = 0; i < length; i++) {
            Map<String, String> obj = list.get(i);
            obj.forEach((key, value) -> {
                // 判断第二行是数字并且大于0
                String number = convertMoney(value);
                if (isPositiveInteger(number) && Integer.parseInt(number) > 0) {
                    String moneyNumber = convertMoney(number);
                    currentLength.set(new BigDecimal(moneyNumber)); // 当前元素是数字
                    if (maxLength.get().compareTo(currentLength.get()) < 0) {
                        maxLength.set(currentLength.get());
                    }

                }
            });
        }

        return maxLength.get();
    }

    /**
     * 查找集合中逾期对应次数
     *
     * @param list 输入的集合
     * @param length 判断的长度
     * @return 出现数组次数合
     */
    public static int findSumLengthOfNumber(List<Map<String,String>> list,int length) {
        if (list == null || list.isEmpty()) {
            return 0;
        }
        AtomicInteger maxLength = new AtomicInteger();

        for (int i = 0; i < length; i++) {
            Map<String, String> obj = list.get(i);
            obj.forEach((key, value) -> {
                String number = convertMoney(value);
                if (isPositiveInteger(number) && Integer.parseInt(number) > 0) {
                    maxLength.addAndGet(1);
                }
            });
        }
        return maxLength.get();
    }


    /**
     * 获取担保人代还
     * 取值：无：
     * 取值：信贷交易信息明细-（非循环贷账户、循环贷账户一、循环贷账户二）所有“管理机构“ 所有管理机构名称，
     * 还款记录表-年份中对应第一行中无出现D字母的账户；有：有出现D字母的账户
     * @param list 还款记录集合
     * @return 当configValue大于analysisMonthLength时 返回analysisMonthLength 否则返回configValue
     */
    public static int getGuarantorRepayment(List<Map<String,String>> list){
        if (list == null || list.isEmpty()) {
            return 0;
        }
        for (Map<String, String> obj : list) {
            if (obj.containsKey("D")) {
                return 1;
            }
        }
        return 0;
    }


    /**
     * 获取担保人代还
     * 取值：无：
     * 取值：信贷交易信息明细-（非循环贷账户、循环贷账户一、循环贷账户二）所有“管理机构“ 所有管理机构名称，
     * 还款记录表-年份中对应第一行中无出现D字母的账户；有：有出现D字母的账户
     * @param list 还款记录集合
     * @return 当configValue大于analysisMonthLength时 返回analysisMonthLength 否则返回configValue
     */
    public static int getSettleDebtsWithCapital(List<Map<String,String>> list){
        if (list == null || list.isEmpty()) {
            return 0;
        }
        for (Map<String, String> obj : list) {
            if (obj.containsKey("Z")) {
                return 1;
            }
        }
        return 0;
    }


    /**
     * set 对象值方法
     * @param detailsDO 对象object
     * @param key parenMap 中的key
     * @param parenMap 存对象属性的map
     * @param parser 字段类和转义方法类似  Integer::parseInt 将String 转成 Integer
     * @param setter 字段的set方法
     * @param getter 字段的get方法
     * @param defaultValue 默认值 某些值map中没有 需要默认值 添加默认值key为null
     * @param <T> 泛型
     */
    public static <T> void accumulate(CreditReportDetailsSaveReqVO detailsDO, String key, Map<String, Object> parenMap,
                                      Function<String, T> parser, BiConsumer<CreditReportDetailsSaveReqVO, T> setter,
                                      Function<CreditReportDetailsSaveReqVO, T> getter, T defaultValue) {

        if (Objects.isNull(key)) {
            // 如果 valueStr 为空，使用默认值
            T existingValue = getter.apply(detailsDO);
            if (existingValue == null) {
                setter.accept(detailsDO, defaultValue);
            } else {
                setter.accept(detailsDO, (T) Integer.valueOf(((Integer) existingValue) + ((Integer) defaultValue)));

            }
        }else {
            Object valueObj =  parenMap.get(key);
            if (Objects.nonNull(valueObj)){
                String valueStr = convertMoney(valueObj.toString());
                try {
                    T value = parser.apply(valueStr);
                    T existingValue = getter.apply(detailsDO);

                    if (existingValue == null) {
                        setter.accept(detailsDO, value);
                    } else {
                        // 需要显式地进行累加逻辑
                        if (value instanceof Integer && existingValue instanceof Integer) {
                            setter.accept(detailsDO, (T) Integer.valueOf(((Integer) existingValue) + ((Integer) value)));
                        } else if (value instanceof BigDecimal && existingValue instanceof BigDecimal) {
                            setter.accept(detailsDO, (T) ((BigDecimal) existingValue).add((BigDecimal) value));
                        } else {
                            // 如果类型不匹配，则抛出异常或者进行其他处理
                            throw new IllegalArgumentException("Unsupported types for accumulation");
                        }
                    }
                } catch (NumberFormatException e) {
                    log.info("Error parsing value for key: " + key + ", value: " + valueStr);
                }
            }
        }
    }

    /**
     * 判断账户是否属于未结清状态
     *  不等于正常并且不等于逾期则表示未结清
     * @param status 逾期 正常 呆帐，转出 销户 结清
     * @return 逾期 (逾期 正常 呆帐，转出)  (未结清)返回false   销户 结清 (结清)返回true
     */
    public static boolean isAccountStatus(String status){
        if(!Objects.equals(status,NORMAL) && !Objects.equals(status,OVERDUE)
          && !Objects.equals(status,BAD_DEBT) && !Objects.equals(status,TURN_OUT)){
            return true;
        }
        return false;
    }



    /**
     * 用于计算金额 4,600
     * 将字符串中非数字部分替换为空字符串。
     * @param money
     * @return
     */
    public static String convertMoney(String money){
        /**
         * 将字符串中非数字部分替换为空字符串。
         *
         * @param str 要处理的字符串。
         * @return 替换后的字符串，只包含数字。  如果输入为null，返回null
         */
            if(!StringUtils.isNotBlank(money)){
                return "0";
            } else if (Objects.equals(money,"null")) {
                return "0";
            }else if (!isPositiveInteger(money)){
                return money.replace(",", "").trim();  // 使用正则表达式替换非数字字符
            }
            return money;
    }

    /**
     * 计算年龄
     * @param value
     * @return
     */
    public static Integer getAge(String value){
        Integer ageFromIdCard = getAgeFromIdCard(value);
        log.info("年龄:{}", ageFromIdCard);
        return ageFromIdCard;
    }

    /**
     * 根据身份证判断年龄
     * @param idCard
     * @return
     */
    public static Integer getAgeFromIdCard(String idCard) {
        if (idCard == null || idCard.isEmpty()) {
            log.info("身份证号码为空");
            return null;
        }

        try {
            String birthDateStr = extractBirthDate(idCard);
            if (birthDateStr == null) return null;

            DateTimeFormatter formatter;
            LocalDate birthDate;

            if (birthDateStr.length() == 8) { // 完整日期 "yyyyMMdd"
                formatter = DateTimeFormatter.ofPattern("yyyyMMdd");
                birthDate = LocalDate.parse(birthDateStr, formatter);

            } else if (birthDateStr.length() == 6) { // 可能存在歧义，例如 "yyMMdd"，需要考虑世纪
                formatter = DateTimeFormatter.ofPattern("yyMMdd");
                LocalDate potentialBirthDate = LocalDate.parse(birthDateStr, formatter);

                // 尝试将年份转换为20世纪或21世纪，选择更合理的年份
                int yearPrefix = (potentialBirthDate.getYear() > LocalDate.now().getYear() % 100) ? 1900 : 2000;
                birthDate = LocalDate.of(potentialBirthDate.getYear() + yearPrefix, potentialBirthDate.getMonthValue(), potentialBirthDate.getDayOfMonth());
            }
            else {
                log.info("身份证号码格式不正确: 出生日期长度错误");
                return null;
            }

            LocalDate currentDate = LocalDate.now();
            Period period = Period.between(birthDate, currentDate);

            return period.getYears();

        } catch (DateTimeParseException e) {
            log.info("身份证号码格式不正确: 日期解析错误: " + e.getMessage());
            return null;
        } catch (IllegalArgumentException e) {
            log.info("身份证号码格式不正确: 参数错误: " + e.getMessage());
            return null;
        } catch (Exception e) {
            log.info("处理身份证号码时发生错误: " + e.getMessage());
            return null;
        }
    }


    /**
     *  转换时间格式
     * @param dateStr 时间字符串
     * @param dateOriginallyFormat 转换前的格式
     * @param dateObjectiveFormat 转换后的格式
     * @return
     */
    public static String formattingDate(String dateStr,String dateOriginallyFormat, String dateObjectiveFormat){
        log.info("日期格式化: {}", dateStr);
        SimpleDateFormat inputFormat = new SimpleDateFormat(dateOriginallyFormat);  // 允许单个数字日期和月份
        SimpleDateFormat outputFormat = new SimpleDateFormat(dateObjectiveFormat);  // 统一输出格式为 yyyy-MM-dd
        try {
            // 解析不规则的日期字符串
            Date date = inputFormat.parse(dateStr);
            // 格式化为标准日期格式
            return outputFormat.format(date);
        } catch (ParseException e) {
            throw new ServiceException(500,"查询记录日期格式不正确");
        }

    }

    /**
     * 判断身份证长度
     * @param idCard
     * @return
     */
    private static String extractBirthDate(String idCard) {
        if (idCard.length() == 18) {
            return idCard.substring(6, 14);
        } else if (idCard.length() == 15) {
            return "19" + idCard.substring(6, 12); // 15位身份证，默认是20世纪
        } else {
            log.info("身份证号码长度不正确");
            return null;
        }
    }

    /**
     * 根据身份证号码获取性别。
     *
     * @param idCard 身份证号码字符串
     * @return "0" 如果是男性， "1" 如果是女性， null 如果身份证号码无效
     */
    public static Integer getGender(String idCard) {

        if (idCard == null || idCard.length() != 18) {
            return null; // 身份证号码无效
        }

        try {
            int genderDigit = Integer.parseInt(idCard.substring(16, 17)); // 获取倒数第二位
            if (genderDigit % 2 == 0) {
                return 1;
            } else {
                return 0;
            }
        } catch (NumberFormatException e) {
            return null; // 身份证号码无效，可能包含非数字字符
        }
    }

    public static String getQueryMaxDateTime(List<String> timeList){
        // 定义时间格式化器
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(YYYY_MM_DD);

        // 使用 stream 将时间字符串转换为 LocalDateTime，并找出最大时间
        LocalDate maxTime = timeList.stream()
                .map(time -> LocalDate.parse(time, formatter))  // 将字符串转换为 LocalDateTime
                .max(LocalDate::compareTo)  // 比较最大时间
                .orElseThrow(() -> new IllegalArgumentException("List is empty"));
        return maxTime.format(formatter);
    }

    /**
     * 判断是否为null 否则返回0
     * @param value
     * @return
     */
    public static String defaultValue(Object value){
        if (Objects.isNull(value)){
            return "0";
        }
        return value.toString();
    }

    public static void main(String[] args) {

        System.out.println(isToday(convert("20250716 11:21:11")));
     }

}
